인스턴스 등록(Register)과 해제(Dispose)의 차이

인스턴스 등록(Register)과 해제(Dispose)의 차이

데이터 분산 서비스(DDS, Data Distribution Service) 아키텍처는 단순한 메시지 전달 미들웨어를 넘어, 네트워크상에 분산된 거대한 ’가상 데이터베이스’를 구축하는 기술이다. 이 가상 데이터베이스, 즉 글로벌 데이터 공간(Global Data Space)을 이해하는 데 있어 가장 중요한 단위는 토픽(Topic) 자체가 아니라, 토픽 내부에서 키(Key)에 의해 식별되는 개별 데이터 객체인 ’인스턴스(Instance)’이다.1

많은 개발자가 DDS를 처음 도입할 때, write() 함수만을 사용하여 데이터를 전송하는 데 집중하곤 한다. 그러나 실시간 시스템의 복잡도가 증가하고 데이터의 생명주기(Lifecycle) 관리가 중요해질수록, DataWriter가 제공하는 세 가지 핵심 연산인 register_instance, unregister_instance, dispose의 명확한 구분과 적절한 활용이 시스템의 성능과 정합성을 결정짓는 핵심 요소로 부상한다. 이 세 연산은 겉보기에는 유사하게 데이터를 관리하는 것처럼 보이지만, 미들웨어 내부에서 작동하는 메커니즘과 네트워크를 통해 전파되는 의미론적(Semantic) 메시지는 근본적으로 다르다.3

본 절에서는 이 세 가지 연산의 기술적 정의와 내부 동작 원리, 그리고 이들이 QoS 정책 및 시스템 리소스와 어떻게 상호작용하는지를 심층적으로 분석한다. 특히, 인스턴스의 상태 전이(State Transition)와 관련하여 개발자가 반드시 숙지해야 할 데이터 무결성 이슈와 성능 최적화 전략을 상세히 기술한다.

1. 인스턴스 관리의 철학적 배경: 글로벌 데이터 공간

DDS의 데이터 중심(Data-Centric) 철학에서 ’인스턴스’는 관계형 데이터베이스의 ’행(Row)’이나 객체지향 프로그래밍의 ’객체(Object)’와 유사한 지위를 갖는다. 예를 들어 ’항공기 트랙(Flight Track)’이라는 토픽이 존재할 때, ‘KE081’, ’OZ101’과 같은 개별 항공편 식별자(Flight ID)는 각 인스턴스를 구분하는 키(Key)가 된다.1

이때 시스템은 단순히 항공기의 위치 좌표를 갱신하는 것을 넘어, 특정 항공기가 ‘탐지되기 시작했다(Creation)’, ‘위치가 변경되었다(Update)’, ’착륙하여 추적 대상에서 사라졌다(Deletion)’라는 생명주기 이벤트를 인지해야 한다. DDS 표준은 이러한 생명주기 관리를 위해 명시적인 API를 제공하며, 각 API는 글로벌 데이터 공간에 대한 서로 다른 ’의도(Intent)’를 표명한다.

  • Register (등록): 로컬 자원을 예약하고 데이터 갱신을 준비하겠다는 ‘성능 최적화’ 및 ’선언’의 의도.
  • Unregister (등록 취소): 해당 인스턴스에 대한 업데이트 책임을 더 이상 지지 않겠다는 ’역할 포기’의 의도.
  • Dispose (폐기): 해당 인스턴스가 물리적 또는 논리적으로 소멸하였음을 알리는 ’삭제’의 의도.3

이러한 의도의 차이는 네트워크 트래픽, 메모리 관리, 그리고 구독자(Subscriber) 측의 데이터 해석에 지대한 영향을 미친다.

2. 인스턴스 등록(Register Instance): 성능과 리소스의 최적화

register_instance 연산은 DDS 미들웨어에게 “내가 곧 특정 키(Key)를 가진 인스턴스의 데이터를 쓸(Write) 예정이니, 필요한 리소스를 미리 할당하고 관리 핸들을 달라“고 요청하는 과정이다.3

2.1 명시적 등록과 암시적 등록의 알고리즘적 차이

DDS 표준에 따르면, 인스턴스 등록은 필수 사항이 아니다. 사용자가 register_instance를 호출하지 않고 write()를 호출하더라도, 미들웨어는 내부적으로 **암시적 등록(Implicit Registration)**을 수행한다. 그러나 고성능 시스템에서는 **명시적 등록(Explicit Registration)**이 강력히 권장되는데, 이는 데이터 경로(Data Path) 상의 알고리즘 복잡도 때문이다.5

등록 방식동작 메커니즘시간 복잡도사용 사례
암시적 등록 (Implicit)write() 호출 시마다 샘플의 키 필드를 직렬화하고, 해시(Hash)를 계산한 후, 내부 맵(Map)을 검색하여 인스턴스 컨텍스트를 찾는다. 존재하지 않으면 생성한다.O(\log n) 또는 해시 충돌 시 그 이상낮은 빈도의 데이터 전송, 키 개수가 적은 경우, 편의성이 중요한 경우
명시적 등록 (Explicit)사전에 register_instance()를 호출하여 InstanceHandle_t를 발급받는다. write() 호출 시 이 핸들을 전달하면 검색 과정을 생략하고 메모리 주소로 직접 접근한다.O(1)레이더 추적, 고빈도 거래(HFT) 등 수천 개 이상의 인스턴스를 고속으로 갱신해야 하는 경우

암시적 등록을 사용할 경우, DataWriter는 매 write 호출마다 키 값을 검사해야 한다. 만약 키 필드가 문자열(String)과 같이 가변 길이를 가지거나 복잡한 구조체라면, 이를 직렬화하고 해시를 계산하는 비용은 CPU 사이클을 상당히 소모하게 된다. 반면, register_instance는 이 비용을 최초 1회만 지불하게 한다. 반환된 InstanceHandle_t는 미들웨어 내부의 인스턴스 관리 구조체를 가리키는 포인터이거나 배열의 인덱스 역할을 하므로, 이후의 write 연산은 단순히 해당 메모리 위치에 데이터를 복사하는 작업으로 단축된다.6

2.2 로컬 리소스 예약과 전파 범위

register_instance의 가장 중요한 특징 중 하나는 이 연산이 **로컬 전용(Local-only)**이라는 점이다.5 DataWriter가 인스턴스를 등록하더라도, 이 사실은 네트워크를 통해 DataReader에게 전파되지 않는다. 즉, register만 수행하고 write를 하지 않은 상태에서는 구독자 측에서 새로운 인스턴스가 생성되었음을 알 수 없다.

이는 등록 행위가 데이터의 가용성(Availability)을 알리는 것이 아니라, DataWriter 내부의 **리소스 예약(Resource Reservation)**에 초점을 맞추고 있기 때문이다. DataWriter는 등록된 인스턴스를 관리하기 위해 RESOURCE_LIMITS QoS 정책의 max_instances 한도 내에서 메모리 슬롯을 할당한다.5 만약 max_instances 한도에 도달한 상태에서 새로운 인스턴스를 등록하려고 시도하면, 설정된 RELIABILITYHISTORY QoS 정책에 따라 연산이 차단(Block)되거나 에러를 반환할 수 있다.7

따라서 register_instance는 시스템의 예측 가능성을 높이는 데 기여한다. 시스템 초기화 단계에서 필요한 모든 주요 인스턴스를 미리 등록해 둠으로써, 런타임 중에 메모리 할당 실패나 리소스 부족으로 인한 지연이 발생할 가능성을 사전에 차단할 수 있다.

3. 인스턴스 해제(Unregister)와 폐기(Dispose)의 심층 비교

DDS를 처음 접하는 개발자가 가장 혼란스러워하는 부분이 바로 unregister_instancedispose의 차이이다. 두 연산 모두 인스턴스와의 상호작용을 끝내는 것처럼 보이지만, 그 대상과 범위, 그리고 시스템에 미치는 영향은 완전히 다르다. 이 둘의 차이를 명확히 구분하는 것은 데이터 무결성을 유지하는 데 필수적이다.

3.1 등록 취소(Unregister): 책임의 이양과 역할의 종료

unregister_instance는 **“작성자(Writer)의 관점”**에서 수행되는 연산이다. 이는 “나는 더 이상 이 인스턴스에 대한 정보를 갱신하지 않겠다“라고 선언하는 것이다.3

  • 의미론적 해석: 다수의 센서가 하나의 대상을 추적하는 상황을 가정해보자. 특정 센서의 시야에서 대상이 사라졌다면, 해당 센서(Writer)는 대상을 더 이상 볼 수 없으므로 unregister를 수행한다. 하지만 대상 자체가 사라진 것인지, 아니면 단지 이 센서의 범위만 벗어난 것인지는 확신할 수 없다. 따라서 unregister는 데이터 자체의 존재 여부에는 판단을 유보하고, 오직 Writer 자신의 역할 종료만을 알린다.
  • 인스턴스 상태 변화: unregister가 호출되면, 미들웨어는 해당 인스턴스를 관리하던 Writer 목록에서 호출한 Writer를 제거한다. 만약 이 Writer가 해당 인스턴스를 담당하던 유일한 Writer였다면, 인스턴스의 상태는 NOT_ALIVE_NO_WRITERS로 전이된다.9 그러나 다른 Writer가 여전히 해당 인스턴스를 등록하고 있다면, 인스턴스 상태는 여전히 ALIVE로 유지된다.
  • 리소스 관리: unregister를 호출한 DataWriter는 해당 인스턴스에 할당했던 로컬 리소스를 해제할 수 있는 권한을 얻는다. 이는 제한된 메모리 자원(max_instances)을 효율적으로 재사용하기 위해 필수적이다.11

3.2 폐기(Dispose): 데이터의 소멸과 글로벌 삭제

반면, dispose는 **“데이터(Data)의 관점”**에서 수행되는 연산이다. 이는 “이 인스턴스는 더 이상 유효하지 않으며, 시스템에서 논리적으로 삭제되었다“라고 선언하는 것이다.3

  • 의미론적 해석: 항공기가 착륙하여 엔진을 껐거나, 시뮬레이션 상에서 탱크가 파괴되었다면, 이 객체는 더 이상 추적할 필요가 없다. 이때는 dispose를 호출하여 시스템 전체에 “이 데이터는 소멸했다“는 사실을 공표해야 한다.
  • 인스턴스 상태 변화: dispose가 호출되면, 해당 정보는 네트워크를 타고 모든 연관된 DataReader에게 전파된다. 이를 수신한 Reader 측에서는 인스턴스의 상태를 NOT_ALIVE_DISPOSED로 변경한다.9 이는 단순히 업데이트가 멈춘 것이 아니라, 데이터 자체가 ’죽었음(Dead)’을 의미한다.
  • 데이터 무결성: dispose는 글로벌 데이터 공간에서의 삭제를 의미하므로 매우 강력한 연산이다. 따라서 OWNERSHIP QoS 정책이 EXCLUSIVE로 설정된 경우, 아무 Writer나 dispose를 할 수 없으며, 오직 현재 인스턴스의 소유권(Ownership)을 가진 Writer만이 이 연산을 수행할 수 있다.14

3.3 비교 요약 테이블

다음 표는 두 연산의 차이를 다각도에서 비교 분석한 것이다.

비교 항목Unregister Instance (등록 취소)Dispose (폐기)
핵심 의미작성자(Writer)의 퇴장: “나는 더 이상 관여하지 않겠다.”데이터(Data)의 소멸: “이 객체는 삭제되었다.”
Instance StateNOT_ALIVE_NO_WRITERS (활성 Writer가 없을 때)NOT_ALIVE_DISPOSED
영향 범위로컬 Writer 및 매칭된 Reader의 Writer 목록 갱신글로벌 데이터 공간 전체 (모든 참여자에게 전파)
QoS 제약소유권과 무관하게 누구나 자신의 등록 취소 가능EXCLUSIVE 소유권일 경우 Owner만 호출 가능
리소스 해제Writer 측 리소스 즉시/지연 회수 가능인스턴스 자체는 삭제되지만, 메타데이터는 유지될 수 있음
SampleInfovalid_data = FALSE (상태 변경 알림 샘플)valid_data = FALSE (상태 변경 알림 샘플)
부활(Resurrection)다시 write하면 새로운 등록으로 간주다시 write하면 ALIVE 상태로 복귀

4. 인스턴스 상태 머신과 Valid Data 플래그의 해석

DDS 애플리케이션 개발에서 버그가 가장 많이 발생하는 지점은 구독자(Subscriber)가 데이터를 수신하고 처리하는 부분이다. disposeunregister가 발생하면 DDS는 상태 변경을 알리기 위해 샘플을 전달하는데, 이때 데이터 페이로드(Payload)의 유효성을 정확히 판단하지 않으면 심각한 오류를 초래할 수 있다.

4.1 Valid Data 플래그의 중요성

DataReaderread()take()를 통해 샘플을 꺼낼 때, 함께 전달되는 SampleInfo 구조체에는 valid_data라는 불리언(Boolean) 플래그가 존재한다.2

  • valid_data = TRUE: 정상적인 데이터 업데이트이다. 페이로드(사용자 정의 구조체)에 유의미한 값이 들어있다.
  • valid_data = FALSE: 이는 데이터 업데이트가 아니라, 인스턴스의 상태(State)가 변경되었음을 알리는 메타데이터 샘플이다. 이때 페이로드 영역의 값은 쓰레기 값이거나, 키(Key) 필드만 유효하고 나머지 필드는 초기화되지 않은 상태일 수 있다.

만약 개발자가 valid_data 플래그를 확인하지 않고 무조건 페이로드에 접근하여 로직을 수행하려 한다면, 이미 삭제된(NOT_ALIVE_DISPOSED) 객체의 좌표를 지도에 그리려 하거나, 널 포인터 역참조와 유사한 논리적 오류를 범하게 된다. 따라서 모든 데이터 수신 로직은 다음과 같은 패턴을 따라야 한다.

// DDS 데이터 수신 처리의 정석적 패턴 (개념 코드)
for (int i = 0; i < samples.length(); ++i) {
if (info[i].valid_data) {
// [ALIVE] 정상 데이터 처리: 객체 위치 업데이트, 값 갱신 등
ProcessUserData(samples[i]);
} else {
// 상태 변경 처리: 데이터는 없고 상태 정보만 있음
if (info[i].instance_state == NOT_ALIVE_DISPOSED) {
// 객체가 삭제됨 -> UI 목록에서 제거, 내부 Map에서 삭제
RemoveObject(samples[i].key);
} else if (info[i].instance_state == NOT_ALIVE_NO_WRITERS) {
// 연결 끊김/센서 오프라인 -> 아이콘을 회색으로 변경하거나 경고 표시
MarkObjectAsOffline(samples[i].key);
}
}
}

4.2 인스턴스 부활 (Resurrection)

흥미로운 점은 NOT_ALIVE_DISPOSED 상태가 영구적이지 않다는 것이다. DDS는 이미 dispose 된 인스턴스라 하더라도, 어떤 DataWriter가 동일한 키(Key)를 사용하여 다시 write()를 호출하면 그 즉시 해당 인스턴스를 ALIVE 상태로 복구시킨다.2 이를 **인스턴스 부활(Resurrection)**이라 부른다.

이 과정에서 SampleInfo 내의 disposed_generation_count가 증가한다. 구독자는 이 카운터를 통해 “아, 이 객체는 과거에 3번 삭제되었다가 다시 나타난 객체구나“라는 사실을 인지할 수 있다. 이는 일시적으로 사라졌다가 다시 나타나는 추적 대상(예: 터널을 통과한 차량)을 처리할 때 유용한 메타데이터가 된다.

5. QoS 정책에 의한 생명주기 자동화

DDS는 개발자가 일일이 unregisterdispose를 호출하는 번거로움을 줄이고, 실수를 방지하기 위해 QoS 정책을 통한 자동화 기능을 제공한다. 그중 가장 핵심적인 것이 WRITER_DATA_LIFECYCLE 정책이다.

5.1 autodispose_unregistered_instances

이 설정은 DataWriter가 인스턴스 등록을 취소(unregister)할 때, 자동으로 dispose를 함께 수행할지 여부를 결정한다.12

  • TRUE (기본값): unregister_instance를 호출하거나 DataWriter가 삭제되면, 미들웨어는 먼저 dispose 메시지를 보내 인스턴스를 소멸시킨 후, unregister 처리를 한다.
  • 장점: Writer가 종료되면(예: 애플리케이션 종료) 자동으로 생성했던 모든 데이터가 정리되므로 깔끔한 시스템 상태를 유지할 수 있다.
  • 위험성: 여러 Writer가 동일한 인스턴스를 공유하는 분산 환경에서, 하나의 애플리케이션이 종료될 때 의도치 않게 공유 데이터를 삭제(dispose)해버려 다른 참여자들에게 데이터가 사라진 것으로 오인하게 만들 수 있다.7
  • FALSE: unregisterdispose를 수행하지 않는다. 인스턴스는 NOT_ALIVE_NO_WRITERS 상태로 남는다. 공유 데이터 환경이나, 데이터의 지속성(Persistence)이 Writer의 생명주기보다 길어야 하는 경우(예: DURABILITYTRANSIENT 이상인 경우)에는 반드시 이 값을 FALSE로 설정해야 한다.

5.2 자동 퍼지(Auto Purge)와 메모리 관리

인스턴스가 NOT_ALIVE 상태가 되었다고 해서 메모리에서 즉시 삭제되는 것은 아니다. DDS는 나중에 늦게 합류하는 참여자(Late Joiner)를 위해, 또는 인스턴스가 부활할 가능성을 대비해 일정 기간 동안 메타데이터를 유지한다. 이를 제어하는 것이 READER_DATA_LIFECYCLEautopurge_nowriter_samples_delayautopurge_disposed_samples_delay QoS이다.4

  • INFINITE (기본값): 명시적으로 메모리 제한(max_instances)에 도달하거나 애플리케이션이 종료될 때까지 정보를 유지한다. 이는 메모리 누수처럼 보일 수 있으나, DDS의 빠른 재검색을 위한 의도된 동작이다.
  • 시간 설정: 설정된 시간이 지나면 미들웨어는 비로소 인스턴스 정보를 내부 맵에서 완전히 삭제(Purge)한다. 이때 인스턴스 핸들(Handle)은 무효화되며, 이후 다시 데이터가 들어오면 새로운 인스턴스로 취급되어 핸들이 새로 발급된다.

6. 종합적 고찰 및 권고 사항

인스턴스 생명주기 관리(Register, Unregister, Dispose)는 DDS를 단순한 통신 파이프라인이 아닌, 분산 상태 관리 도구로 활용하게 하는 핵심 메커니즘이다. 성공적인 DDS 시스템 설계를 위해 다음의 권고 사항을 준수할 것을 제안한다.

  1. 명시적 등록의 습관화: 시스템 성능 예측 가능성을 높이기 위해, 가능한 한 register_instance를 사용하여 핸들을 미리 확보하고 이를 write에 활용하라. 이는 특히 CPU 부하가 높은 임베디드 환경에서 O(\log n)O(1)로 줄이는 중요한 최적화 기법이다.
  2. Dispose의 신중한 사용: dispose는 “삭제“다. 단순히 센서가 꺼진 것인지, 객체가 정말 소멸한 것인지 구분하여 사용해야 한다. 센서가 꺼진 경우에는 unregister가 적합하며, 객체가 소멸한 경우에만 dispose를 사용하라.
  3. QoS 기본값의 함정 탈피: autodispose_unregistered_instances가 기본적으로 TRUE임에 유의하라. 다중 Writer 환경에서는 이로 인해 예기치 않은 데이터 삭제가 발생할 수 있으므로, 시스템 아키텍처에 맞게 명시적으로 FALSE로 설정하는 것을 고려해야 한다.
  4. 구독자 로직의 견고성 확보: valid_data 플래그 확인은 선택이 아닌 필수다. 상태 변경 알림(NOT_ALIVE)을 적절히 처리하지 않으면, 화면에 삭제된 유령 데이터가 계속 남아있거나 잘못된 메모리 접근으로 프로그램이 비정상 종료될 수 있다.

결론적으로, register는 성능을 위한 준비이고, dispose는 데이터의 논리적 종결이며, unregister는 참여자의 퇴장이다. 이 세 가지 개념을 명확히 구분하고 적절히 조합하여 사용하는 것이야말로 견고하고 효율적인 데이터 중심 시스템을 구축하는 지름길이다.

7. 참고 자료

  1. Tutorial on the OMG Data Distribution Service, http://www.dre.vanderbilt.edu/~gokhale/OMG_RTWS06/00-T1-1_Giddings.pdf
  2. Data Distribution Service (DDS) - Object Management Group (OMG), https://www.omg.org/spec/DDS/1.4/PDF
  3. Data Distribution Service for Real-Time Systems Specification - Object Management Group (OMG), https://www.omg.org/spec/DDS/1.1/PDF/
  4. Instance Resources, Dispose, and Unregister | Data Distribution Service (DDS) Community RTI Connext Users, https://community.rti.com/content/forum-topic/instance-resources-dispose-and-unregister
  5. 34.14 Managing Instances (Working with Keyed Data Types) - RTI Community, https://community.rti.com/static/documentation/connext-dds/current/doc/manuals/connext_dds_professional/users_manual/users_manual/Managing_Data_Instances__Working_with_Ke.htm
  6. Register the Instance and Use the InstanceHandle When Writing for Better Performance | Data Distribution Service (DDS) Community RTI Connext Users, https://community.rti.com/best-practices/register-instance-and-use-instancehandle-when-writing-better-performance
  7. CoreDX DDS Sample and Instance Management - Twin Oaks Computing, Inc, https://www.twinoakscomputing.com/wp/CoreDX_DDS_Instance_Management.pdf
  8. Configuring Resource Limits in Connext DDS Micro - RTI Community, https://community.rti.com/kb/configuring-resource-limits-connext-dds-micro
    1. Reading and Writing Data — The Data Distribution Service Tutorial, https://download.zettascale.online/www/docs/Vortex/html/ospl/DDSTutorial/readandwrite.html
  9. RTI Connext Modern C++ API: dds::sub::status::InstanceState Class Reference, https://community.rti.com/static/documentation/connext-dds/current/doc/api/connext_dds/api_cpp2/classdds_1_1sub_1_1status_1_1InstanceState.html
  10. RTI Connext DDS Micro C API: max_instances, https://community.rti.com/static/documentation/connext-micro/2.4.14/doc/api_c/html/group__DDSUserManuals__ResourceModule__dwqos__max__instances.html
  11. Understanding Instance States | Data Distribution Service (DDS) Community RTI Connext Users, https://community.rti.com/kb/understanding-instance-states
  12. 3.4.7. SampleInfo - 3.4.1 - eProsima Fast DDS, https://fast-dds.docs.eprosima.com/en/3.x/fastdds/dds_layer/subscriber/sampleInfo/sampleInfo.html
  13. 43.8 Accessing and Managing Instances (Working with Keyed Data Types) - RTI Community, https://community.rti.com/static/documentation/connext-dds/current/doc/manuals/connext_dds_professional/users_manual/users_manual/AccessingManagingInstances.htm
  14. 20.1.4.4. InstanceStateKind - 3.4.1 - eProsima Fast DDS, https://fast-dds.docs.eprosima.com/en/3.x/fastdds/api_reference/dds_pim/subscriber/instancestatekind.html
  15. RTI Connext Traditional C++ API: DDS_SampleInfo Struct Reference - RTI Community, https://community.rti.com/static/documentation/connext-dds/current/doc/api/connext_dds/api_cpp/structDDS__SampleInfo.html
  16. WRITER_DATA_LIFECYCLE QoS Parameter [DDS Foundation Wiki], https://www.omgwiki.org/ddsf/doku.php?id=ddsf:public:guidebook:06_append:02_quality_of_service:writer_data_lifecycle